package com.iqilu.ksd.utils;

import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.List;

/**
 * Created by Coofee on 2016/10/13.
 */

public class JSONUtils {

    private static final String TAG = "JSONUtils";

    private static Gson gson = null;

    static {
        if (gson == null) {
            gson = new Gson();
        }
    }

    enum NodeType {
        NORMAL, ARRAY, ARRAYITEM
    }

    public static <T> T requestDetail(String jsonString, String filter, Class<T> classOfT) {
        Log.i(TAG, "requestDetail jsonString=" + jsonString);
        JSONObject jsonObject = null;
        try {
            jsonObject = new JSONObject(jsonString);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        JSONObject joResult = JSONUtils.filterObject(jsonObject, filter);
        T result = null;
        try {
            result = gson.fromJson(joResult.toString(), classOfT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static <T> T requestList(String jsonString, String filter, TypeToken<T> typeToken) {
        Log.i(TAG, "requestList jsonString=" + jsonString);
        JSONObject jsonObject = null;
        try {
            jsonObject = new JSONObject(jsonString);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        JSONArray jsonArray = JSONUtils.filterArray(jsonObject, filter);
        T result = null;
        try {
            result = gson.fromJson(jsonArray.toString(), typeToken.getType());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String filterString(JSONObject jsonObject, String filter) {
        filter = trim(filter);
        JSONObject upperObject = getUpperObject(jsonObject, filter);
        String lastNodeName = getLastNodeName(filter);
        if (upperObject != null && !TextUtils.isEmpty(lastNodeName)) {
            return upperObject.optString(lastNodeName);
        } else {
            return null;
        }
    }

    public static String filterString(String jsonString, String filter) {
        filter = trim(filter);
        JSONObject jsonObject = null;
        try {
            jsonObject = new JSONObject(jsonString);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        JSONObject upperObject = getUpperObject(jsonObject, filter);
        String lastNodeName = getLastNodeName(filter);
        if (upperObject != null && !TextUtils.isEmpty(lastNodeName)) {
            return upperObject.optString(lastNodeName);
        } else {
            return null;
        }
    }

    public static boolean filterBoolean(JSONObject jsonObject, String filter, boolean fallback) {
        filter = trim(filter);
        JSONObject upperObject = getUpperObject(jsonObject, filter);
        String lastNodeName = getLastNodeName(filter);
        if (upperObject != null && !TextUtils.isEmpty(lastNodeName)) {
            return upperObject.optBoolean(lastNodeName, fallback);
        } else {
            return fallback;
        }
    }

    public static int filterInt(String jsonString, String filter, int fallback) {
        JSONObject jsonObject = null;
        try {
            jsonObject = new JSONObject(jsonString);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        filter = trim(filter);
        JSONObject upperObject = getUpperObject(jsonObject, filter);
        String lastNodeName = getLastNodeName(filter);
        if (upperObject != null && !TextUtils.isEmpty(lastNodeName)) {
            return upperObject.optInt(lastNodeName, fallback);
        } else {
            return fallback;
        }
    }


    public static JSONArray filterArray(JSONObject jsonObject, String filter) {
        filter = trim(filter);
        JSONObject upperObject = getUpperObject(jsonObject, filter);
        String lastNodeName = getLastNodeName(filter);
        if (upperObject != null && !TextUtils.isEmpty(lastNodeName)) {
            return upperObject.optJSONArray(lastNodeName);
        } else {
            return null;
        }
    }

    public static JSONObject filterObject(JSONObject jsonObject, String filter) {
        JSONObject result = null;
        if (jsonObject == null || TextUtils.isEmpty(filter)) {
            return result;
        }
        String[] nodes = filter.split("\\.");
        JSONObject tmp = jsonObject;
        int count = 0;
        for (String node : nodes) {
            if (tmp != null && !TextUtils.isEmpty(node)) {
                switch (nodeType(node)) {
                    default:
                    case ARRAY:
                        return result;
                    case ARRAYITEM:
                        node = node.replaceAll("\\[\\d+\\]", "");
                        JSONArray array = tmp.optJSONArray(node);
                        if (array != null) {
                            tmp = array.optJSONObject(0);
                        }
                        break;
                    case NORMAL:
                        tmp = tmp.optJSONObject(node);
                        break;
                }
                count++;
            }
        }
        if (count == nodes.length) {
            result = tmp;
        }
        return result;
    }
    private static NodeType nodeType(String nodename) {
        if (nodename.matches(".*?\\[\\d+\\]$")) {
            return NodeType.ARRAYITEM;
        }
        if (nodename.matches(".*?\\[\\]$")) {
            return NodeType.ARRAY;
        }
        return NodeType.NORMAL;
    }

    private static JSONObject getUpperObject(JSONObject jsonObject, String filter) {
        if (jsonObject == null || TextUtils.isEmpty(filter)) {
            return null;
        }
        if (filter.contains(".")) {
            String upperFilter = filter.substring(0, filter.lastIndexOf("."));
            return filterObject(jsonObject, upperFilter);
        } else {
            return jsonObject;
        }
    }

    private static String trim(String filter) {
        if (filter.startsWith(".")) {
            filter = filter.substring(1);
        }
        if (filter.endsWith(".")) {
            filter = filter.substring(0, filter.length() - 1);
        }
        return filter;
    }

    private static String getLastNodeName(String filter) {
        if (TextUtils.isEmpty(filter)) {
            return filter;
        } else {
            String lastNodeName = null;
            if (filter.contains(".")) {
                lastNodeName = filter.substring(filter.lastIndexOf(".") + 1);
            } else {
                lastNodeName = filter;
            }
            return lastNodeName;
        }
    }
}
